package walletsyslogic

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go.uber.org/zap"
	"navi-mumbai/app/rpc/model/pg/usercenter"
	"navi-mumbai/app/rpc/model/pg/wallet"
	pbuser "navi-mumbai/app/rpc/usercenter/pb"
	"navi-mumbai/common/key/appsflyerkey"
	"navi-mumbai/common/key/dbkey"
	"navi-mumbai/common/key/userkey"
	"navi-mumbai/common/key/walletkey"
	"navi-mumbai/common/utils"
	"navi-mumbai/common/xerr"
	"navi-mumbai/third/appsflyer"
	"runtime/debug"
	"strconv"
	"strings"

	"navi-mumbai/app/rpc/wallet/internal/svc"
	"navi-mumbai/app/rpc/wallet/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateDepositResultLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateDepositResultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateDepositResultLogic {
	return &UpdateDepositResultLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// 更新充值结果
func (l *UpdateDepositResultLogic) UpdateDepositResult(in *pb.UpdateDepositResultReq) (*pb.UpdateDepositResultResp, error) {
	defer utils.RecoverPanic()

	// 查询充值流水
	var df *wallet.UserDepositFlow
	var err error
	df, err = l.svcCtx.UserDepositFlowModel.FindOne(l.ctx, in.FlowNo)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		if err == wallet.ErrNotFound {
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowNotFound, "flow not found")
		}
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	// 检查状态
	switch in.State {
	case walletkey.DepositFlowStateWait:
		if df.State != walletkey.DepositFlowStateInit {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
		}
	case walletkey.DepositFlowStateSuccess:
		if df.State != walletkey.DepositFlowStateWait && df.State != walletkey.DepositFlowStateInit {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
		}
	case walletkey.DepositFlowStateFailed:
		if df.State != walletkey.DepositFlowStateInit && df.State != walletkey.DepositFlowStateWait {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
		}
	default:
		l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
	}

	var rsp pb.UpdateDepositResultResp
	switch in.State {
	case walletkey.DepositFlowStateSuccess:
		// 查询用户钱包
		var uw *wallet.UserWallet
		uw, err = l.svcCtx.UserWalletModel.FindOneByUidMoneyType(l.ctx, in.Uid, df.MoneyType)
		if err != nil && err != wallet.ErrNotFound {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}

		err = l.svcCtx.UserWalletModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
			// 更新支付流水
			err2 := l.svcCtx.UserDepositFlowModel.UpdateTrans(ctx, tx, df.FlowNo, in.State, in.ExternalFlowNo, in.PayGwFlowNo)
			if err2 != nil {
				l.Logger.Errorf("err == ", zap.Error(err2))
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
			}
			// 更新钱包
			if uw == nil { // 未创建钱包
				uw = &wallet.UserWallet{
					Uid:       df.Uid,
					MoneyType: df.MoneyType,
					Amount:    df.MoneyAmount,
					State:     dbkey.Enable,
				}
				_, err2 = l.svcCtx.UserWalletModel.InsertTrans(ctx, tx, uw)
				if err2 != nil {
					l.Logger.Errorf("err == ", zap.Error(err2))
					return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
				}
			} else { // 已创建钱包
				// 更新钱包余额
				err2 = l.svcCtx.UserWalletModel.AddAmountTrans(ctx, tx, df.MoneyAmount, uw.Id, uw.Uid, uw.MoneyType)
				if err2 != nil {
					l.Logger.Errorf("err == ", zap.Error(err2))
					return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
				}
			}
			return nil
		})
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, err
		}
		l.RepoertAppsFlyer(df)

	case walletkey.DepositFlowStateFailed, walletkey.DepositFlowStateWait:
		// 更新支付流水
		err = l.svcCtx.UserDepositFlowModel.UpdateState(l.ctx, df.FlowNo, in.State, in.ExternalFlowNo, in.ErrMsg, in.PayGwFlowNo)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
	}
	sInMoneyAmount := decimal.NewFromInt(df.MoneyAmount).Div(decimal.NewFromInt(100)).StringFixedBank(2)
	// 先注释走kafka的逻辑，改用直接插入数据库
	// l.after(in.Uid, in.State, walletkey.GetMoneyNameByMoneyType(df.MoneyType), sInMoneyAmount)
	// 充值成功之后，插入通知消息
	l.afterInsertNotifyMsg(in.Uid, in.State, walletkey.GetMoneyNameByMoneyType(df.MoneyType), sInMoneyAmount)
	//如果是邀请的用户，需要返还佣金给上级
	l.afterInviteReturn(in.Uid, in.State, df.MoneyAmount)
	return &rsp, nil
}

// 充值成功，给邀请者返回佣金
func (l *UpdateDepositResultLogic) afterInviteReturn(uid int64, state int64, moneyAmount int64) {
	defer l.RecoverPanic()
	// 充值失败，直接return
	if state != walletkey.DepositFlowStateSuccess {
		return
	}
	// 金币需要除以100
	moneyAmount = decimal.NewFromInt(moneyAmount).Div(decimal.NewFromInt(walletkey.MoneyScale)).IntPart()

	l.Logger.Infof("afterInviteReturn start... uid: %d, moneyAmount: %d", uid, moneyAmount)
	err := l.svcCtx.UserInviteModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		// 查询邀请的配置
		userInviteConfigList, err := l.svcCtx.UserInviteConfigModel.Find(l.ctx)
		if err != nil {
			l.Logger.Errorf("afterInviteReturn == ", zap.Error(err))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		if userInviteConfigList == nil || len(userInviteConfigList) < 1 {
			l.Logger.Errorf("afterInviteReturn == ", zap.Error(err))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		// 默认取第一条邀请配置
		userInviteConfig := userInviteConfigList[0]
		// 获取往上返的所有上级
		uids := make([]int64, 0)
		superiorLevel := userInviteConfig.SuperiorLevel
		// 默认只返上级
		if superiorLevel < 0 {
			superiorLevel = 1
		}
		// 根据uid，查询直接上级, 如果没有查到，则说明没有邀请者
		info, err := l.svcCtx.UserInviteModel.FindOneByUid(l.ctx, uid)
		if info == nil || err != nil {
			l.Logger.Errorf("afterInviteReturn. err == %+v", err)
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		uids = append(uids, info.Pid)
		curPid := info.Pid
		// 往上返回级数
		for superiorLevel > 1 {
			curParent, err := l.svcCtx.UserInviteModel.FindOneByUid(l.ctx, curPid)
			if err != nil {
				l.Logger.Errorf("err == ", zap.Error(err))
				// 如果没查询到数据，则跳出循环
				break
			}
			if curParent == nil {
				break
			}
			uids = append(uids, curParent.Pid)
			curPid = curParent.Pid
			superiorLevel--
		}
		depositDirectLogic := NewDepositDirectLogic(l.ctx, l.svcCtx)
		var ratioArr []int64 = l.GetRatios(userInviteConfig.ReturnRatio)
		var rebateType int64 = userkey.InviteDirectlyRebateType
		for i, userUid := range uids {
			if i > 0 {
				rebateType = userkey.InviteUnDirectlyRebateType
			}
			var ratio int64 = 10
			if i < len(ratioArr) {
				ratio = ratioArr[i]
			}
			// 每一级返10% 具体可调整
			sInRetrunRatio := decimal.NewFromInt(ratio).Div(decimal.NewFromInt(100))
			dMoneyAmount := decimal.NewFromInt(moneyAmount)
			iMoneyAmount := dMoneyAmount.Mul(sInRetrunRatio).IntPart()
			l.Logger.Infof("afterInviteReturn. iMoneyAmount: %d", iMoneyAmount)
			// 新增邀请订单流水
			userInviteOrderFlow := &usercenter.UserInviteOrderFlow{
				Uid:         uid,
				Pid:         userUid, // 上级
				MoneyType:   walletkey.UsingCurrencyType,
				MoneyAmount: iMoneyAmount,              // B端币种金额
				Type:        userkey.InviteDepositType, // 类型1：注册，2：充值
				RebateType:  rebateType,
			}
			l.Logger.Infof("afterInviteReturn. UserInviteOrderFlowModel.Insert userInviteOrderFlow: %+v", userInviteOrderFlow)
			_, err = l.svcCtx.UserInviteOrderFlowModel.Insert(l.ctx, userInviteOrderFlow)
			if err != nil {
				l.Logger.Errorf("[afterHandleInvite] UserInviteOrderFlowModel.Insert. err == ", zap.Error(err))
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
			}
			// 发送充值
			resp, err := depositDirectLogic.DepositDirect(&pb.DepositDirectReq{
				Uid:            userUid, // 级上级
				MoneyType:      walletkey.UsingCurrencyType,
				MoneyAmount:    decimal.NewFromInt(iMoneyAmount).StringFixedBank(2),
				CurrencyType:   0,
				CurrencyAmount: "",
				PayChannelId:   walletkey.PayChannelIdSystem,
				ExFlow:         "",
			})
			if err != nil {
				l.Logger.Errorf("err == ", zap.Error(err))
				l.Logger.Errorf("afterInviteReturn uid:%d err:%v", uid, err)
				return xerr.NewGrpcErrCodeMsg(xerr.ServerCommonError, err.Error())
			}
			l.Logger.Infof("afterInviteReturn. resp: %+v", resp)

		}
		// 如果已经是有效用户，则直接返回
		if info.IsEffectiveUser == dbkey.Enable {
			l.Logger.Infof("afterInviteReturn. is effective user info: %+v", info)
			return nil
		}
		// 再判断累计充值金额，是否足够，如果不足够，直接返回
		totalAmount := decimal.NewFromInt(info.TotalAmount).Div(decimal.NewFromInt(walletkey.MoneyScale)).IntPart() + moneyAmount
		if totalAmount < userInviteConfig.RechargeLimit {
			// 累计充值，没有达到要求，
			l.Logger.Infof("afterInviteReturn. totalAmount not enough.  totalAmount: %+v", totalAmount)
			// 更新累计充值
			info.TotalAmount = decimal.NewFromInt(totalAmount).Mul(decimal.NewFromInt(walletkey.MoneyScale)).IntPart()
			err = l.svcCtx.UserInviteModel.Update(l.ctx, info)
			if err != nil {
				l.Logger.Errorf("[afterHandleInvite] UserInviteModel.Update. err == ", zap.Error(err))
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
			}
			return nil
		}
		// 如果满足要求，则需要更新记录
		info.TotalAmount = decimal.NewFromInt(totalAmount).Mul(decimal.NewFromInt(walletkey.MoneyScale)).IntPart()
		info.IsEffectiveUser = dbkey.Enable
		err = l.svcCtx.UserInviteModel.Update(l.ctx, info)
		if err != nil {
			l.Logger.Errorf("[afterHandleInvite] UserInviteModel.Update. err == ", zap.Error(err))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		// 判断充值金额
		upUid := uids[0] // 表示直接上级
		// 新增邀请订单流水
		userInviteOrderFlow := &usercenter.UserInviteOrderFlow{
			Uid:         uid,
			Pid:         upUid, // 上级
			MoneyType:   walletkey.UsingCurrencyType,
			MoneyAmount: userInviteConfig.RechargeReturnMoney, // B端币种金额 充值返回金额
			Type:        userkey.InviteDepositType,            // 类型1：注册，2：充值
			RebateType:  userkey.InviteEffectiveUserRebateType,
		}
		l.Logger.Infof("afterInviteReturn. UserInviteOrderFlowModel.Insert userInviteOrderFlow: %+v", userInviteOrderFlow)
		_, err = l.svcCtx.UserInviteOrderFlowModel.Insert(l.ctx, userInviteOrderFlow)
		if err != nil {
			l.Logger.Errorf("[afterHandleInvite] UserInviteOrderFlowModel.Insert. err == ", zap.Error(err))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		// 发送充值
		resp, err := depositDirectLogic.DepositDirect(&pb.DepositDirectReq{
			Uid:            upUid, // 级上级
			MoneyType:      walletkey.UsingCurrencyType,
			MoneyAmount:    decimal.NewFromInt(userInviteConfig.RechargeReturnMoney).StringFixedBank(2),
			CurrencyType:   0,
			CurrencyAmount: "",
			PayChannelId:   walletkey.PayChannelIdSystem,
			ExFlow:         "",
		})
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			l.Logger.Errorf("afterInviteReturn uid:%d err:%v", uid, err)
			return xerr.NewGrpcErrCodeMsg(xerr.ServerCommonError, err.Error())
		}
		l.Logger.Infof("afterInviteReturn. resp: %+v", resp)
		return nil

	})
	if err != nil {
		l.Logger.Errorf("[afterHandleInvite] err == ", zap.Error(err))
		return
	}
	l.Logger.Infof("afterInviteReturn success.")
}

// 充值成功之后，插入通知消息
func (l *UpdateDepositResultLogic) afterInsertNotifyMsg(uid int64, state int64, moneyName string, moneyAmount string) {
	defer l.RecoverPanic()
	title := ""
	var msgType int64 = 0
	var msgContent userkey.UserNotifyMsgContent1
	switch state {
	case walletkey.DepositFlowStateSuccess:
		title = userkey.UserNotifyMsgTitleDepositSuccess01EnIn
		msgType = userkey.UserNotifyMsgTypeDepositSuccess01
		msgContent = userkey.UserNotifyMsgContent1{
			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentDepositSuccess01EnIn, moneyAmount, moneyName),
			Url:      "",
			PagePath: "",
		}
	case walletkey.DepositFlowStateFailed:
		title = userkey.UserNotifyMsgTitleDepositFailed02EnIn
		msgType = userkey.UserNotifyMsgTypeDepositFailed02
		msgContent = userkey.UserNotifyMsgContent1{
			Text:     userkey.UserNotifyMsgContentDepositFailed02EnIn,
			Url:      "",
			PagePath: "",
		}
	default:
		return
	}

	var cBuf []byte
	cBuf, err := json.Marshal(msgContent)
	if err != nil {
		l.Logger.Errorf("afterInsertNotifyMsg after json.Marshal(msgContent) err:%v", err)
		return
	}

	in := &pbuser.AddUserNotifyMsgReq{
		Uid:        uid,
		Title:      title,
		MsgType:    msgType,
		MsgContent: string(cBuf),
	}

	_, err = l.AddUserNotifyMsg(in)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
	}
	l.Logger.Errorf("afterInsertNotifyMsg sucess.")
}

// 新增通知消息
func (l *UpdateDepositResultLogic) AddUserNotifyMsg(in *pbuser.AddUserNotifyMsgReq) (*pbuser.AddUserNotifyMsgResp, error) {
	err := l.svcCtx.UserAccountModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		unm := usercenter.UserNotifyMsg{
			Uid:        in.Uid,
			MsgType:    in.MsgType,
			MsgContent: in.MsgContent,
			IsRead:     dbkey.Enable,
			Title:      in.Title,
		}
		l.Logger.Infof("AddUserNotifyMsg. in: %+v", in)
		// 增加消息
		_, err2 := l.svcCtx.UserNotifyMsgModel.InsertTrans(ctx, tx, &unm)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		// 更新消息条数
		err2 = l.svcCtx.UserNotifyMsgStatModel.AddMsgCount(ctx, tx, in.Uid, 1)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		return nil
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}
	return &pbuser.AddUserNotifyMsgResp{}, nil
}

//func (l *UpdateDepositResultLogic) after(uid int64, state int64, moneyName, moneyAmount string) {
//	var kqMsg kqmsg.KqAddUserNotifyMsg
//	var msgContent userkey.UserNotifyMsgContent1
//	switch state {
//	case walletkey.DepositFlowStateSuccess:
//		kqMsg = kqmsg.KqAddUserNotifyMsg{
//			Uid:     uid,
//			Title:   userkey.UserNotifyMsgTitleDepositSuccess01EnIn,
//			MsgType: userkey.UserNotifyMsgTypeDepositSuccess01,
//		}
//
//		msgContent = userkey.UserNotifyMsgContent1{
//			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentDepositSuccess01EnIn, moneyAmount, moneyName),
//			Url:      "",
//			PagePath: "",
//		}
//
//	case walletkey.DepositFlowStateFailed:
//		kqMsg = kqmsg.KqAddUserNotifyMsg{
//			Uid:     uid,
//			Title:   userkey.UserNotifyMsgTitleDepositFailed02EnIn,
//			MsgType: userkey.UserNotifyMsgTypeDepositFailed02,
//		}
//
//		msgContent = userkey.UserNotifyMsgContent1{
//			Text:     userkey.UserNotifyMsgContentDepositFailed02EnIn,
//			Url:      "",
//			PagePath: "",
//		}
//
//	default:
//		return
//	}
//
//	var cBuf []byte
//	cBuf, err := json.Marshal(msgContent)
//	if err != nil {
//		l.Logger.Errorf("UpdateDepositResultLogic after json.Marshal(msgContent) err:%v", err)
//		return
//	}
//	kqMsg.MsgContent = string(cBuf)
//
//	var kqMsgBuf []byte
//	kqMsgBuf, err = json.Marshal(kqMsg)
//	if err != nil {
//		l.Logger.Errorf("UpdateDepositResultLogic after json.Marshal(kqMsg) err:%v", err)
//		return
//	}
//
//	err = l.svcCtx.KqAddUserNotifyMsgClient.Push(string(kqMsgBuf))
//	if err != nil {
//		l.Logger.Errorf("UpdateDepositResultLogic after Push err:%v", err)
//		return
//	}
//	return
//}

func (l *UpdateDepositResultLogic) RepoertAppsFlyer(df *wallet.UserDepositFlow) {
	// 捕获异常
	defer l.RecoverPanic()
	// 查询交易流水，判断充值成功的记录，以此判断用户是第一次充值，还是第二次充值
	// page == 0 pageSize == 0,默认查询前10条
	// pagChannelId == 0 默认查询第三方支付
	userDepositFlows, err := l.svcCtx.UserDepositFlowModel.Find(context.Background(), df.Uid, []int64{walletkey.DepositFlowStateSuccess}, 0, 0, 0, nil, nil, 0, 0)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return
	}
	// 查询用户信息， 获取appsflyer_id
	userAccount, err := l.svcCtx.UserAccountModel.FindOne(l.ctx, df.Uid)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return
	}
	appsFlyerUid := userAccount.AppsFlyerUid
	if len(userDepositFlows) == 1 {
		// 首次充值
		appsflyer.ReportAppsFlyerEvent(l.ctx, appsflyerkey.FirsPayment, appsFlyerUid, "")
	} else if len(userDepositFlows) >= 2 {
		// 多次付费
		appsflyer.ReportAppsFlyerEvent(l.ctx, appsflyerkey.MultiplePayments, appsFlyerUid, "")
	}
	// 判断付费等级， 如果eventInfo == nil 时， 则没有达到相应的等级，否则达到相应等级，则上报等级事件
	eventInfo := appsflyer.GetEventName(df.MoneyAmount)
	if eventInfo != nil {
		appsflyer.ReportAppsFlyerEvent(l.ctx, eventInfo.EventName, appsFlyerUid, "")
	}
}

func (l *UpdateDepositResultLogic) RecoverPanic() {
	if err := recover(); err != nil {
		l.Logger.Errorf("Panic Recover", zap.Any("Error", err))
		debug.PrintStack()
	}
}

func (l *UpdateDepositResultLogic) GetRatios(ratio string) []int64 {
	var res []int64 = make([]int64, 0)
	ratioArrs := strings.Split(ratio, ",")
	for _, rStr := range ratioArrs {
		if rStr == "" {
			continue
		}
		n, _ := strconv.Atoi(rStr)
		res = append(res, int64(n))
	}
	return res
}
